package model;

import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Set;
import java.util.TreeSet;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import javax.persistence.Transient;

import controller.util.DateHelper;

@Entity
public class Datentraeger extends ModelBase implements Serializable {

	private static final long serialVersionUID = -2952735933715107252L;

	@Column
	private String name;

	@OneToMany(mappedBy = "datentraeger")
	private Set<Film> filme = new TreeSet<Film>();
	@Transient
	private Date creationDate;

	@Transient
	private DatentraegerInfo info = new DatentraegerInfo();

	public Datentraeger(java.lang.String string) {
		setName(string);
		setCreationDate(DateHelper.createTodayMidnight());
		initInfo();
	}

	public Datentraeger(Long id, String name, Date creationDate) {
		setId(id);
		setName(name);
		setCreationDate(creationDate);
		initInfo();
	}

	public Datentraeger(String name, Date creationDate) {
		setName(name);
		setCreationDate(creationDate);
		initInfo();
	}

	private void initInfo() {
		info.setId("" + getId());
		info.setName(name);
	}

	public void setName(String string) {
		if (string == null || string.trim().length() == 0) {
			throw new IllegalArgumentException(
					"name must not be null or empty!");
		}
		this.name = string;
	}

	public String getName() {
		return name;
	}

	public void setCreationDate(Date creationDate) {
		if (creationDate == null) {
			throw new IllegalArgumentException("creationDate must not be null!");
		}
		this.creationDate = (Date) creationDate.clone();
	}

	public Date getCreationDate() {
		return (Date) creationDate.clone();
	}

	public boolean isNew() {
		return getId() == null ? true : false;
	}

	public Datentraeger addFilm(Film film) {
		if (film == null) {
			throw new IllegalArgumentException("film must not be null!");
		}
		filme.add(film);
		return this;
	}

	public Datentraeger removeFilm(Film film) {
		if (film == null) {
			throw new IllegalArgumentException("film must not be null!");
		}
		filme.remove(film);
		return this;
	}

	public Collection<Film> getFilme() {
		return Collections.unmodifiableCollection(filme);
	}

	public Film getFilmByIndex(int index) {
		if (index < 0 || index >= filme.size()) {
			throw new IndexOutOfBoundsException(String.format(
					"index %d is out of bounds!", index));
		}
		int i = 0;
		for (Film film : filme) {
			if (i == index) {
				return film;
			}
			i++;
		}
		throw new IllegalStateException(String.format(
				"index %d is inside bounds, but cannot be found!", index));
	}

	public Film getFilmByName(String name) {
		if (name == null || name.trim().length() == 0) {
			throw new IllegalArgumentException(
					"name must not be null or empty!");
		}
		for (Film film : filme) {
			if (film.getName().equalsIgnoreCase(name)) {
				return film;
			}
		}
		return null;
	}

	public Collection<Film> getFilmeByHauptdarsteller(String hauptdarsteller) {
		if (hauptdarsteller == null || hauptdarsteller.trim().length() == 0) {
			throw new IllegalArgumentException(
					"hauptdarsteller must not be null or empty!");
		}
		Set<Film> result = new TreeSet<Film>(new Film.FilmNameComparator());
		for (Film film : filme) {
			if (film.getName().equalsIgnoreCase(name)) {
				result.add(film);
			}
		}
		if (result.isEmpty()) {
			return Collections.emptySet();
		}
		return result;
	}

	@Override
	public String toString() {
		return String.format("%s {name=%s, #filme=%d}%n", getClass().getName(),
				name, filme.size());
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + (filme == null ? 0 : filme.hashCode());
		result = prime * result + (name == null ? 0 : name.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (getClass() != obj.getClass()) {
			return false;
		}
		Datentraeger other = (Datentraeger) obj;
		if (filme == null) {
			if (other.filme != null) {
				return false;
			}
		} else if (!filme.equals(other.filme)) {
			return false;
		}
		if (name == null) {
			if (other.name != null) {
				return false;
			}
		} else if (!name.equals(other.name)) {
			return false;
		}
		return true;
	}

	public DatentraegerInfo getInfo() {
		return info;
	}

	public class DatentraegerInfo {
		private String id;
		private String name;

		public void setId(String id) {
			this.id = id;
		}

		public void setName(String name) {
			this.name = name;
		}

		public String getId() {
			return id;
		}

		public String getName() {
			return name;
		}
	}

	@Override
	public int compareTo(Datentraeger other) {
		return name.compareTo(other.getName());
	}

	public static final class DatentraegerNameComparator implements
			Comparator<Datentraeger> {

		@Override
		public int compare(Datentraeger left, Datentraeger right) {
			int result;
			if ((result = left.getName().compareTo(right.getName())) == 0) {
				result = left.getName().compareTo(right.getName());
			}
			return result;
		}

	}

}
